/**
 * Copyright [2019] [LiBo/Alex of copyright liboware@gmail.com ]
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hyts.infodb.file.service.file.impl;

import com.google.common.base.Preconditions;
import com.hyts.infodb.enums.StatusTypeEnum;
import com.hyts.infodb.error.subclass.ServiceException;
import com.hyts.infodb.file.bean.directory.DirectoryBO;
import com.hyts.infodb.file.bean.directory.DirectoryVO;
import com.hyts.infodb.file.bean.file.FileBO;
import com.hyts.infodb.file.bean.file.FileVO;
import com.hyts.infodb.file.config.UploadFileConfiguration;
import com.hyts.infodb.file.dao.file.FileRelateDAO;
import com.hyts.infodb.file.service.directory.DirectoryService;
import com.hyts.infodb.file.service.file.FileExtService;
import com.hyts.infodb.file.service.file.FileService;
import com.hyts.infodb.utils.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Objects;

/**
 * @project-name:infodb
 * @package-name:com.hyts.infodb.file.service.file.impl
 * @author:LiBo/Alex
 * @create-date:2020-01-16 17:59
 * @copyright:libo-alex4java
 * @email:liboware@gmail.com
 * @description: 文件服务执行扩展服务实现类
 */
@Slf4j
@Service
public class FileExtServiceImpl implements FileExtService {


    @Autowired
    UploadFileConfiguration uploadConfigure;


    @Autowired
    FileRelateDAO fileRelateDAO;


    @Autowired
    FileService fileService;

    @Autowired
    DirectoryService directoryService;

    /**
     * 上传(本地)文件
     * @param file
     * @return
     */
    @Transactional
    @Override
    public FileVO uploadLocal(MultipartFile file,Long bizNo,Long directoryId) {
        //基础路径 - 根据当前的操作系统环境进行相关的服务赋值路径
        String basePath = uploadConfigure.getBasePath();
        //获取文件保存路径
        String folder = FileUtils.getFolder();
        // 获取前缀为"FL_" 长度为20 的文件名  FL_eUljOejPseMeDg86h.png
        String fileName = FileUtils.getFileName() + FileUtils.getFileNameSub(file.getOriginalFilename());
        try {
            //生成目录操作服务
            Path filePath = Files.createDirectories(Paths.get(basePath, folder));
            log.info("创建生产目录地址-->{}", filePath);
            //写入文件
            Path fullPath = Paths.get(basePath, folder, fileName);
            log.info("创建生产全局目录地址-->{}", fullPath);
            Files.write(fullPath, file.getBytes(), StandardOpenOption.CREATE);
            //保存文件信息
            FileBO fileBO = new FileBO();
            fileBO.setFileName(fileName); // 获取生成得文件计算文件值
            DirectoryBO directoryBO = new DirectoryBO();
            directoryBO.setId(directoryId);
            fileBO.setFilePath(filePath.toString()); // 获取本地全局得绝对路径(默认得地址)
            if(Objects.nonNull(directoryId)){
                DirectoryVO directoryVO = directoryService.loadDirectory(directoryBO);
                if(Objects.nonNull(directoryVO)){
                    fileBO.setFilePath(directoryVO.getContent().getPath()); // 设置得全局地址
                }
            }
            fileBO.setFileSize(file.getSize()); //获取本地文件大小
            fileBO.setFileType(file.getContentType()); //文件类型
            fileBO.setBizNo(bizNo);
            fileBO.setDirectoryId(directoryId);
            fileBO.setFileOrginName(file.getOriginalFilename());
            //fileInfo.setMd5(FileUtils.md5File(fullPath.toString()));
            fileService.saveFile(fileBO); //
        } catch (Exception e) {
            Path path = Paths.get(basePath, folder);
            log.error("写入文件异常,删除文件!", e);
            try {
                Files.deleteIfExists(path);
            } catch (IOException e1) {
                log.error("删除文件出现失败!",e);
            }
        }
        return new FileVO();
    }

    /**
     * 下载（本地）文件
     * @param file
     * @return
     */
    @Override
    public FileVO downloadLocal(FileBO file, HttpServletResponse response) {
        Preconditions.checkNotNull(file,"传入得文件不允许为空!");
        Preconditions.checkNotNull(file.getId(),"传入文件的标识不允许为空!");
        Preconditions.checkArgument(file.getIsRemote() ==
                StatusTypeEnum.REMOTE.getValue().byteValue(),"传入的下载文件必须为本地文件非远程oss文件!");
        FileVO fileVO = fileService.loadFile(file);
        if(Objects.nonNull(fileVO)){
            //设置响应头
            try {
                response.setContentType("application/force-download");// 设置强制下载不打开
                response.addHeader("Content-Disposition", "attachment;fileName=" +
                        new String(fileVO.getContent().getFileOrginName().getBytes("UTF-8"), "ISO8859-1"));// 设置文件名
                response.setHeader("Context-Type", "application/xmsdownload");
                //判断文件是否存在
                File fileDownload = new File(Paths.get(file.getFilePath(),file.getFileName()).toString());
                if (fileDownload.exists()) {
                    byte[] buffer = new byte[1024];
                    try (
                         FileInputStream fis = new FileInputStream(fileDownload);
                         BufferedInputStream bis = new BufferedInputStream(fis);
                        ){
                        OutputStream os = response.getOutputStream();
                        int i = bis.read(buffer);
                        while (i != -1) {
                            os.write(buffer, 0, i);
                            i = bis.read(buffer);
                        }
                        log.info("下载成功{}",fileDownload.getPath());
                    } catch (Exception e) {
                        throw new ServiceException("下载文件失败!",e);
                    }
                }
            } catch (UnsupportedEncodingException e) {
                log.info("下载文件出现异常",e);
            }
        }
        return fileVO;
    }

    /**
     * 查看文件
     * @param file
     * @return
     */
    @Override
    public InputStream lookFile(FileBO file) {
        Path path = Paths.get(file.getFilePath(), file.getFileName());
        try {
            return Files.newInputStream(path);
        } catch (IOException e) {
            log.error("查看图片信息失败!",e);
        }
        return null;
    }

    /**
     * 删除文件
     * @param file
     * @return
     */
    @Override
    public boolean removeFileLocal(FileBO file) {
        try {
            boolean result = fileService.deleteFile(file);
            if(result){
                Files.deleteIfExists(Paths.get(file.getFilePath()+ File.separator+file.getFileName()));
            }
            return result;
        } catch (IOException e) {
            log.error("删除文件失败!",e);
            return false;
        }
    }
}
